package com.lagou.gateway.filter;

import com.lagou.gateway.dao.TokenRepository;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.ArrayList;
import java.util.List;

/**
 * 网关统一的token验证
 *
 * @author pangu
 */
@Slf4j
@Data
@Component
@ConfigurationProperties(prefix = "auth")
public class AuthFilter implements GlobalFilter, Ordered {

	private List<String> ignoreUrl = new ArrayList<>();

	@Autowired
	TokenRepository tokenRepository;

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

		//　如果在忽略的url里，则跳过
		String path = replacePrefix(exchange.getRequest().getURI().getPath());
		String requestUrl = exchange.getRequest().getURI().getRawPath();
		if (ignore(path) || ignore(requestUrl)) {
			return chain.filter(exchange);
		}

		// 验证token是否有效
		ServerHttpResponse resp = exchange.getResponse();
		List<HttpCookie> tokenCookie = exchange.getRequest().getCookies().get("token");
		if(CollectionUtils.isEmpty(tokenCookie)){
			return unauthorized(resp, "没有携带Token信息！");
		}
		String token = tokenCookie.stream().findAny().toString();

		if (tokenRepository.getByToken(token) == null) {
			return unauthorized(resp, "token已过期或验证不正确！");
		}
		return chain.filter(exchange);
	}

	/**
	 * 检查是否忽略url
	 * @param path 路径
	 * @return boolean
	 */
	private boolean ignore(String path) {
		return ignoreUrl.stream()
				.map(url -> url.replace("/**", ""))
				.anyMatch(path::startsWith);
	}

	/**
	 * 移除模块前缀
	 * @param path 路径
	 * @return String
	 */
	private String replacePrefix(String path) {
		if (path.startsWith("/mate")) {
			return path.substring(path.indexOf("/",1));
		}
		return path;
	}

	private Mono<Void> unauthorized(ServerHttpResponse response, String msg) {
		DataBuffer wrap = response.bufferFactory().wrap(msg.getBytes());
		response.setStatusCode(HttpStatus.UNAUTHORIZED);
		return response.writeWith(Mono.just(wrap));
	}

	@Override
	public int getOrder() {
		return 0;
	}

}

